package bme.andraskindler.treenventory.activity;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Bitmap;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.os.Build;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.animation.AlphaAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;
import android.widget.TextView;
import android.widget.Toast;
import bme.andraskindler.treenventory.R;
import bme.andraskindler.treenventory.TreenventoryApplication;
import bme.andraskindler.treenventory.fragment.LocationDialogFragment;
import bme.andraskindler.treenventory.fragment.ResolutionFragment;
import bme.andraskindler.treenventory.provider.MyLocationManager;
import bme.andraskindler.treenventory.provider.MyLocationManager.LocationResult;
import bme.andraskindler.treenventory.widget.CameraSurfaceView;
import bme.andraskindler.treenventory.widget.CompassView;

import com.actionbarsherlock.app.SherlockFragmentActivity;
import com.actionbarsherlock.view.Menu;
import com.google.android.gms.maps.model.LatLng;


/**
 * 
 * @author andraskindler
 * A fényképezést megvalósító activity. A kamera képét egy CameraSurfaceView jeleníti meg, a fényképezéshez meg kell érinteni az előnézeti képet.
 * A kamera képétől jobbra kézzel vezérelhető a mérési magasság.
 * A beállítások között a vakumód, a felbontás és a korrekció állítható.
 * A felület alján egy iránytű látható, melyet a CompassView vezérlő valósít meg, az adatokat egy SensorManager példánytól kéri el.
 */
public class CameraActivity extends SherlockFragmentActivity {

	// views
	private RelativeLayout mGrid;
	private TextView mOrientation;
	private CompassView mCompassView;
	private float mAzimuth;

	// sensor variables
	private static SensorManager mSensorService;
	private Sensor mSensor;

	// photo
	private boolean mFlash;

	// location
	private LatLng mCoords;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		final RelativeLayout root = (RelativeLayout) getLayoutInflater().inflate(R.layout.activity_camera, null);
		setContentView(root);

		mFlash = false;
		final float density = getResources().getDisplayMetrics().density;
		final float displaywidth = getResources().getDisplayMetrics().widthPixels;
		final float displayheight = getResources().getDisplayMetrics().heightPixels - 40 * density;
		final int margin = (int) (5 * density);
		final LayoutParams lp = new LayoutParams((int) displaywidth, (int) displayheight);
		lp.setMargins(margin, margin, 5 * margin, 10 * margin);

		// setting up camerasurfaceview
		final CameraSurfaceView cameraSurfaceView = new CameraSurfaceView(this);
		cameraSurfaceView.setLayoutParams(lp);
		cameraSurfaceView.setOnTouchListener(new OnTouchListener() {

			public boolean onTouch(View v, MotionEvent event) {
				if (event.getAction() == MotionEvent.ACTION_DOWN) {
					if (mCoords != null) {
						if (TreenventoryApplication.getInstance().isConnected()) {
							final SharedPreferences preferences = getSharedPreferences(OptionsActivity.SETTINGS, Context.MODE_PRIVATE);
							cameraSurfaceView.shoot(mFlash, preferences.getInt(OptionsActivity.SETTINGS_RESOLUTION, 1), CameraSurfaceView.PICTURE_PROCESS);
							TreenventoryApplication.getInstance().getmService().requestPhoto();
						} else
							Toast.makeText(getApplication(), "Please connect to a device via bluetooth", Toast.LENGTH_SHORT).show();
					} else {
						Toast.makeText(getApplicationContext(), "Az alkalmazás még nem találta meg a pozíciót", Toast.LENGTH_SHORT).show();
					}
				}
				return true;
			}
		});
		root.addView(cameraSurfaceView);

		getSupportActionBar().setHomeButtonEnabled(true);
		getSupportActionBar().setDisplayHomeAsUpEnabled(true);

		final AlphaAnimation fade_in = new AlphaAnimation(.0f, 1.0f);
		fade_in.setFillAfter(true);
		fade_in.setDuration(250);

		final AlphaAnimation fade_out = new AlphaAnimation(1.0f, .0f);
		fade_out.setFillAfter(true);
		fade_out.setDuration(250);

		final View indicator = root.findViewById(R.id.camera_slider_indicator);
		final TextView heightindicator = (TextView) root.findViewById(R.id.camera_height_indicator);
		heightindicator.bringToFront();
		final View slider = root.findViewById(R.id.camera_slider);
		slider.setOnTouchListener(new OnTouchListener() {
			int currentheight = 0;

			@SuppressLint("NewApi")
			public boolean onTouch(View v, MotionEvent event) {
				switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
					heightindicator.startAnimation(fade_in);
					return true;
				case MotionEvent.ACTION_MOVE:
					if (event.getY() < slider.getBottom() && event.getY() > slider.getTop()) {
						currentheight = (int) (((slider.getHeight() - event.getY()) / slider.getHeight()) * 100);
						heightindicator.setText(currentheight + "");
						final int move = (int) ((event.getY() / slider.getHeight()) * slider.getHeight());
						if (TreenventoryApplication.getCurrentApiVersion() >= Build.VERSION_CODES.HONEYCOMB) {
							indicator.setTranslationY(move);
						} else {
							final TranslateAnimation anim = new TranslateAnimation(0, 0, 0, move);
							anim.setFillAfter(true);
							anim.setDuration(0);
							indicator.startAnimation(anim);
						}
					}
					return true;
				case MotionEvent.ACTION_UP:
					heightindicator.startAnimation(fade_out);
					final Editor editor = getSharedPreferences(OptionsActivity.SETTINGS, Context.MODE_PRIVATE).edit();
					editor.putInt(OptionsActivity.SETTINGS_HEIGHT, currentheight);
					editor.commit();
					return true;
				default:
					break;
				}

				return false;
			}
		});

		mOrientation = TextView.class.cast(root.findViewById(R.id.camera_tv_focusdistance));

		mGrid = (RelativeLayout) getLayoutInflater().inflate(R.layout.camera_grid, null);
		mGrid.setLayoutParams(lp);
		root.addView(mGrid);

		final LocationResult locationResult = new LocationResult() {
			@Override
			public void gotLocation(Location location) {
				if (location != null) {
					mCoords = new LatLng(location.getLatitude(), location.getLongitude());
				} else {
					finish();
				}
			}
		};

		boolean locationAcquireable = new MyLocationManager().getLocation(this, locationResult);
		if (!locationAcquireable) {
			LocationDialogFragment.newInstance().show(getSupportFragmentManager(), LocationDialogFragment.class.getCanonicalName());
		}

		initSensor(root);
	}

	/**
	 * 
	 * @param parent - a compass, mely megjeleníti az orientációt.
	 * 
	 * A szenzor inicializálásáért felelős függvény.
	 */
	@SuppressWarnings("deprecation")
	private void initSensor(final View parent) {
		mSensorService = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
		mSensor = mSensorService.getDefaultSensor(Sensor.TYPE_ORIENTATION);
		if (mSensor != null) {
			mSensorService.registerListener(mySensorEventListener, mSensor, SensorManager.SENSOR_DELAY_NORMAL);
		} else {
			Toast.makeText(this, "Orientation sensor not found", Toast.LENGTH_LONG).show();
			finish();
		}
		mCompassView = (CompassView) parent.findViewById(R.id.camera_compass);
	}

	private SensorEventListener mySensorEventListener = new SensorEventListener() {

		public void onAccuracyChanged(Sensor sensor, int accuracy) {
			// not used
		}

		public void onSensorChanged(SensorEvent event) {
			String orientation = "";
			final float azimuth = event.values[0];
			if (azimuth > 337.5f || azimuth <= 22.5f)
				orientation = "észak";
			else if (azimuth > 22.5f && azimuth <= 67.5f)
				orientation = "északkelet";
			else if (azimuth > 67.5f && azimuth <= 112.5f)
				orientation = "kelet";
			else if (azimuth > 112.5f && azimuth <= 157.5f)
				orientation = "délkelet";
			else if (azimuth > 157.5f && azimuth <= 202.5f)
				orientation = "dél";
			else if (azimuth > 202.5f && azimuth <= 247.5f)
				orientation = "délnyugat";
			else if (azimuth > 247.5f && azimuth <= 292.5f)
				orientation = "nyugat";
			else
				orientation = "északnyugat";

			mAzimuth = azimuth;
			mCompassView.dataChanged(azimuth);
			mOrientation.setText("Orientáció: " + orientation + " (" + (int) azimuth + "º " + (int) ((azimuth - (int) azimuth) * 60) + "')");
		}
	};

	/**
	 * 
	 * @param bmp - az elkészült fotó.
	 * 
	 * A fényképezés callbackje, ez indítja el a mérési algoritmust és activity-t.
	 */
	public void pictureTaken(final Bitmap bmp) {
		final Intent intent = new Intent(this, MeasureActivity.class);
		intent.putExtra("angle", mAzimuth);
		intent.putExtra(LatLng.class.getCanonicalName(), mCoords);
		TreenventoryApplication.setCameraImage(bmp);
		startActivity(intent);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		getSupportMenuInflater().inflate(R.menu.menu_camera, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(com.actionbarsherlock.view.MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menu_flash:
			mFlash = !mFlash;
			item.setChecked(mFlash);
			return true;
		case R.id.menu_grid:
			mGrid.setVisibility(mGrid.getVisibility() == View.INVISIBLE ? View.VISIBLE : View.INVISIBLE);
			return true;
		case R.id.menu_resolution:
			ResolutionFragment.newInstance().show(getSupportFragmentManager(), "fragment_resolution_dialog");
			return true;
		case R.id.menu_manual:
			finish();
			startActivity(new Intent(this, CalibrateActivity.class));
			return true;
		case android.R.id.home:
			finish();
			return true;
		case R.id.menu_correction:
			item.setChecked(!item.isChecked());
			final Editor editor = getSharedPreferences(OptionsActivity.SETTINGS, Context.MODE_PRIVATE).edit();
			editor.putBoolean(OptionsActivity.SETTINGS_CORRECTION, item.isChecked()).commit();
			return true;
		default:
			break;
		}
		return true;
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
		if (mSensor != null) {
			mSensorService.unregisterListener(mySensorEventListener);
		}
	}

}
